package com.dd.cloud.user.service.ca.impl;


import com.ancun.netsign.client.NetSignClient;
import com.ancun.netsign.model.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.CaConstants;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.Base64Util;
import com.dd.cloud.common.utils.ValidatorUtils;
import com.dd.cloud.user.DTO.ca.ConcatSignAddReq;
import com.dd.cloud.user.DTO.ca.VisaWaitFileUploadReq;
import com.dd.cloud.user.entity.ca.CaDoctor;
import com.dd.cloud.user.entity.ca.CaServerApi;
import com.dd.cloud.user.mapper.ca.CaDoctorMapper;
import com.dd.cloud.user.service.ca.ICaDoctorService;
import com.dd.cloud.user.service.ca.ICaServerApiService;
import com.dd.cloud.user.service.file.IFileInfoService;
import com.dd.cloud.user.util.HuaWeiOBSUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 医生CA账号信息 服务实现类
 * </p>
 *
 * @author czg
 * @since 2024-01-22
 */
@Service
@Slf4j
public class CaDoctorServiceImpl extends ServiceImpl<CaDoctorMapper, CaDoctor> implements ICaDoctorService {

    @Autowired
    private ICaServerApiService caServerApiService;
    @Autowired
    private IFileInfoService fileInfoService;

    /**
     * @description 个人ca认证
     * @param :
     * @return void
     * @author czg
     * @date 2024/1/22 15:50
    */
    @Override
    public void authCaDoctor() {
        QueryWrapper<CaServerApi> qw = new QueryWrapper<>();
        qw.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qw);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);

        QueryWrapper<CaDoctor> qs = new QueryWrapper<>();
        qs.lambda().eq(CaDoctor::getStatus, CaConstants.Status.NORMAL)
                .eq(CaDoctor::getType, CaConstants.AuthType.NOAUTH);
        List<CaDoctor> caDoctors = list(qs);
        if (caDoctors == null || caDoctors.isEmpty()){
            throw new ZekeException("没有未认证的用户");
        }
        caDoctors.forEach(item ->{
            AuthInput authInput = new AuthInput();
            authInput.setIdCardNo(item.getIdCard());
            authInput.setRealName(item.getName());
            authInput.setMobile(item.getPhone());
            NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                    caServerApi.getAppid(), caServerApi.getPrivateKey());
            ApiRespBody<AuthOutput> authOutputApiRespBody = netSignClient.personAuthMobile3(authInput);
            if (authOutputApiRespBody == null || authOutputApiRespBody.getCode() != 100000){
                throw new ZekeException(item.getName() + "用户ca认证失败, 原因" + authOutputApiRespBody.getMsg());
            }
            AuthOutput data = authOutputApiRespBody.getData();
            if (data == null){
                throw new ZekeException(item.getName() + "用户ca认证失败, 原因: 返回信息为空");
            }
            item.setSerialNo(data.getSerialNo());
            boolean b = updateById(item);
            if (!b){
                throw new ZekeException(item.getName() + "用户ca认证失败, 原因: 认证流水号修改失败");
            }
        });
    }

    /**
     * @description 重新发送认证验证码
     * @param id:
     * @return void
     * @author czg
     * @date 2024/1/22 17:14
    */
    @Override
    public void captchaResend(Integer id) {
        CaDoctor caDoctor = getById(id);
        if (caDoctor == null){
            throw new ZekeException("id不存在");
        }
        if (StringUtils.isBlank(caDoctor.getSerialNo())){
            throw new ZekeException("没有认证流水号, 当前用户请先认证");
        }
        QueryWrapper<CaServerApi> qw = new QueryWrapper<>();
        qw.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qw);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        ApiRespBody<Void> voidApiRespBody = netSignClient.resendAuthCaptcha(caDoctor.getSerialNo());
        if (voidApiRespBody == null || voidApiRespBody.getCode() != 100000){
            throw new ZekeException("重新发送验证码失败, 原因" + voidApiRespBody.getMsg());
        }
    }

    /**
     * @description 效验验证码
     * @param id: 已发送认证的用户数据id
     * @return void
     * @author czg
     * @date 2024/1/22 17:38
    */
    @Override
    public void captchaVerify(Integer id, String captcha) {
        CaDoctor caDoctor = getById(id);
        if (caDoctor == null){
            throw new ZekeException("id不存在");
        }
        if (StringUtils.isBlank(caDoctor.getSerialNo())){
            throw new ZekeException("没有认证流水号, 当前用户请先认证");
        }
        QueryWrapper<CaServerApi> qw = new QueryWrapper<>();
        qw.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qw);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        SealAuthInput input = new SealAuthInput();
        input.setSealNo(caDoctor.getSealNo());
        input.setCaptcha(captcha);
        ApiRespBody<AuthOutput> respBody = netSignClient.verifyCaptcha(caDoctor.getSerialNo(), captcha);
        if (respBody == null || respBody.getCode() != 100000){
            throw new ZekeException("效验验证码失败, 原因" + respBody.getMsg());
        }
        AuthOutput data = respBody.getData();
        if (data == null || data.getResult() == 2){
            throw new ZekeException("认证失败");
        }
        caDoctor.setType(CaConstants.AuthType.AUTH);
        boolean b = updateById(caDoctor);
        if (!b){
            throw new ZekeException("认证成功, 数据修改失败");
        }
    }

    /**
     * @description 添加用户
     * @param account:
     * @return void
     * @author czg
     * @date 2024/1/22 17:46
    */
    @Override
    public void addPersonalUser(String account, String signPwd) {
        QueryWrapper<CaDoctor> qw = new QueryWrapper<>();
        qw.lambda().eq(CaDoctor::getAccount, account)
                .eq(CaDoctor::getStatus, CaConstants.Status.NORMAL)
                .eq(CaDoctor::getType, CaConstants.AuthType.AUTH);
        CaDoctor caDoctor = getOne(qw);
        caDoctor.setSignPwd(signPwd);
        if (caDoctor == null){
            throw new ZekeException("用户不存在");
        }
        if (StringUtils.isBlank(caDoctor.getSerialNo())){
            throw new ZekeException("没有认证流水号, 当前用户请先认证");
        }
        QueryWrapper<CaServerApi> qs = new QueryWrapper<>();
        qs.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qs);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        UserInput input = new UserInput();
        input.setAccount(account);
        input.setSerialNo(caDoctor.getSerialNo());
        input.setName(caDoctor.getName());
        input.setIdCard(caDoctor.getIdCard());
        input.setSignPwd(caDoctor.getSignPwd());
        ApiRespBody<UserSeal> respBody = netSignClient.addPersonalUserV2(input);
        if (respBody == null || respBody.getCode() != 100000){
            throw new ZekeException("添加个人用户失败, 原因" + respBody.getMsg());
        }
        UserSeal data = respBody.getData();
        if (data != null){
            caDoctor.setSealNo(data.getSealNo());
        }
        boolean b = updateById(caDoctor);
        if (!b){
            throw new ZekeException("添加用户成功, 数据修改失败");
        }
    }

    /**
     * @description 创建印章
     * @param account:
     * @return void
     * @author czg
     * @date 2024/1/23 16:54
    */
    @Override
    public void createSeal(String account) {
        QueryWrapper<CaDoctor> qw = new QueryWrapper<>();
        qw.lambda().eq(CaDoctor::getAccount, account)
                .eq(CaDoctor::getStatus, CaConstants.Status.NORMAL)
                .eq(CaDoctor::getType, CaConstants.AuthType.AUTH);
        CaDoctor caDoctor = getOne(qw);
        if (caDoctor == null){
            throw new ZekeException("用户不存在");
        }
        if (StringUtils.isBlank(caDoctor.getSerialNo())){
            throw new ZekeException("没有认证流水号, 当前用户请先认证");
        }
        QueryWrapper<CaServerApi> qs = new QueryWrapper<>();
        qs.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qs);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        UserSealInput input = new UserSealInput();
        input.setAccount(account);
        input.setIsDefault(1);
        input.setScaling(0.7F);
        input.setColor("FF0000");
        input.setSealName("签字专用章");
        DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String format = LocalDateTime.now().format(sdf);
        input.setSealNo(format + caDoctor.getId());
//        if (!StringUtils.isBlank(caDoctor.getSealNo())){
//            input.setSealNo(caDoctor.getSealNo());
//        }
        ApiRespBody<UserSealOutput> respBody = netSignClient.createSeal(input);
        if (respBody == null || respBody.getCode() != 100000){
            throw new ZekeException("添加个人用户印章失败, 原因" + respBody.getMsg());
        }
        caDoctor.setSealNo(input.getSealNo());
        caDoctor.setSealUrl(null);
        boolean b = updateById(caDoctor);
        if (!b){
            throw new ZekeException("添加用户印章成功, 数据修改失败");
        }
    }

    /**
     * @description 查询印章
     * @param account: 
     * @return void
     * @author czg
     * @date 2024/1/22 18:00
    */
    @Override
    public String getUserSeals(String account) {
        QueryWrapper<CaDoctor> qw = new QueryWrapper<>();
        qw.lambda().eq(CaDoctor::getAccount, account)
                .eq(CaDoctor::getStatus, CaConstants.Status.NORMAL)
                .eq(CaDoctor::getType, CaConstants.AuthType.AUTH);
        CaDoctor caDoctor = getOne(qw);
        if (caDoctor == null){
            throw new ZekeException("用户不存在");
        }
        //当前有印章地址, 直接返回, 没有的话查询接口再保存印章
        if (!StringUtils.isBlank(caDoctor.getSealUrl())){
            return caDoctor.getSealUrl();
        }
        if (StringUtils.isBlank(caDoctor.getSerialNo())){
            throw new ZekeException("没有认证流水号, 当前用户请先认证");
        }
        QueryWrapper<CaServerApi> qs = new QueryWrapper<>();
        qs.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qs);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        UserSealInput input = new UserSealInput();
        input.setAccount(account);
        if (!StringUtils.isBlank(caDoctor.getSealNo())){
            input.setSealNo(caDoctor.getSealNo());
        }
        ApiRespBody<UserSealOutput> respBody = netSignClient.getUserSeals(input);
        if (respBody == null || respBody.getCode() != 100000){
            throw new ZekeException("添加个人用户失败, 原因" + respBody.getMsg());
        }
        UserSealOutput data = respBody.getData();
        if (data != null){
            List<UserSeal> seals = data.getList();
            if (!seals.isEmpty()){
                caDoctor.setSealUrl(seals.get(0).getSealUrl());
                boolean b = updateById(caDoctor);
                if (!b){
                    throw new ZekeException("添加用户成功, 数据修改失败");
                }
            }
        }
        return caDoctor.getSealUrl();
    }

    /**
     * @description 上传待签署文件
     * @param req:
     * @return void
     * @author czg
     * @date 2024/1/22 18:13
    */
    @Override
    public ApiRespBody<ContractOutput> createContract(VisaWaitFileUploadReq req) {
        QueryWrapper<CaServerApi> qs = new QueryWrapper<>();
        qs.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qs);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        ContractInput input = new ContractInput();

        input.setContractNo(req.getContractNo());
        input.setContractName(req.getContractName());
        input.setSignOrder(1);
        input.setValidityTime(10);
        List<FileDto> fileDtos = new ArrayList<>();
        req.getContractFiles().forEach(item ->{
            FileDto fileDto = new FileDto();
            fileDto.setFileName(item.getOriginalFilename());
            try {
                fileDto.setFileInputStream(item.getInputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            fileDtos.add(fileDto);
        });
        input.setContractFiles(fileDtos);
        ApiRespBody<ContractOutput> respBody = netSignClient.createContract(input);
        return respBody;
//        if (respBody == null || respBody.getCode() != 100000){
//            throw new ZekeException("上传签署文件失败, 原因" + respBody.getMsg());
//        }
    }

    /**
     * @description 添加签约方
     * @param req:
     * @return void
     * @author czg
     * @date 2024/1/22 18:28
    */
    @Override
    public String addSigner(ConcatSignAddReq req) {
        QueryWrapper<CaDoctor> qw = new QueryWrapper<>();
        qw.lambda().eq(CaDoctor::getAccount, req.getAccount())
                .eq(CaDoctor::getStatus, CaConstants.Status.NORMAL)
                .eq(CaDoctor::getType, CaConstants.AuthType.AUTH);
        CaDoctor caDoctor = getOne(qw);
        if (caDoctor == null){
            throw new ZekeException("用户不存在");
        }
        QueryWrapper<CaServerApi> qs = new QueryWrapper<>();
        qs.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qs);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        List<ContractUserInput> contracs = new ArrayList<>();
        ContractUserInput input = new ContractUserInput();
        BeanUtils.copyProperties(req, input);
        input.setValidateType(2);
        List<UserSignStrategyInput> signStrategyInputs = new ArrayList<>();
        req.getSignStrategyList().forEach(item ->{
            UserSignStrategyInput signStrategyInput = new UserSignStrategyInput();
            signStrategyInput.setSignX(item.getSignX());
            signStrategyInput.setSignY(item.getSignY());
            signStrategyInput.setAttachNo(1);
            signStrategyInput.setLocationMode(2);
            signStrategyInput.setSignPage(1);
            signStrategyInput.setOffsetX(0.9);
            signStrategyInput.setOffsetY(0.9);

            signStrategyInputs.add(signStrategyInput);

        });

        input.setSignStrategyList(signStrategyInputs);
        //input.setSignType(2);
        contracs.add(input);

        ApiRespBody<ContractOutput> respBody = netSignClient.addSigner(contracs);
        if (respBody == null){
            throw new ZekeException("添加签署方失败, 返回为空");
        }
        if (respBody.getCode() != 100000){
            throw new ZekeException("添加签署方失败, 原因" + respBody.getMsg());
        }
        ContractOutput data = respBody.getData();
        if (data == null){
            throw new ZekeException("签署成功, 返回为空");
        }
        return data.getPreviewUrl();
    }

    /**
     * @description 下载合同
     * @param contractNo: 合同编号
     * @return String
     * @author czg
     * @date 2024/1/24 9:38
    */
    @Override
    public String downloadContract(String contractNo) {
        QueryWrapper<CaServerApi> qs = new QueryWrapper<>();
        qs.lambda().eq(CaServerApi::getStatus, CaConstants.Status.NORMAL);
        List<CaServerApi> list = caServerApiService.list(qs);
        if (list == null || list.isEmpty()){
            throw new ZekeException("查询CA服务API接口失败");
        }
        CaServerApi caServerApi = list.get(0);
        NetSignClient netSignClient = new NetSignClient(caServerApi.getServer(),
                caServerApi.getAppid(), caServerApi.getPrivateKey());
        ApiRespBody<DownloadContractOutput> respBody = netSignClient.forceDownloadContract(contractNo, null,1, "/temp");

        if (respBody == null){
            throw new ZekeException("下载合同失败, 返回为空");
        }
        if (respBody.getCode() != 100000){
            throw new ZekeException("下载合同失败, 原因" + respBody.getMsg());
        }
        DownloadContractOutput data = respBody.getData();
        File file = Base64Util.byte2File(data.getData(), "./temp", contractNo + ".pdf");
        String fileUrl = HuaWeiOBSUtil.uploadFile(file);
        return fileUrl;
    }

    /**
     * @description 大道处方线上签方, 1,上传签约文件 2,添加签约方 3,上传签约文件链接
     * @param req:
     * @return String
     * @author czg
     * @date 2024/2/19 15:18
    */
    @Override
    public String caSign(VisaWaitFileUploadReq req) {
        //上传签约文件
        ApiRespBody<ContractOutput> contract = createContract(req);
        if (100055 == contract.getCode()) {
            //合同编号已存在, 直接下载
            //获取合同文件链接
            String downloadContract = downloadContract(req.getContractNo());
            return downloadContract;
        }
        if (contract == null || contract.getCode() != 100000) {
            throw new ZekeException("上传签署文件失败, 原因" + contract.getMsg());
        }
        QueryWrapper<CaDoctor> qw = new QueryWrapper<>();
        qw.lambda().eq(CaDoctor::getStatus, CaConstants.Status.NORMAL)
                .eq(CaDoctor::getType, CaConstants.AuthType.AUTH);
        List<CaDoctor> caDoctorList = list(qw);
        if (caDoctorList == null || caDoctorList.isEmpty()){
            throw new ZekeException("用户不存在");
        }
        ConcatSignAddReq concatSignAddReq = new ConcatSignAddReq();
        concatSignAddReq.setAccount(caDoctorList.get(0).getAccount());
        concatSignAddReq.setContractNo(req.getContractNo());
        concatSignAddReq.setSignType(2);
        ConcatSignAddReq.SignStrategy strategy = new ConcatSignAddReq.SignStrategy();
        strategy.setSignX(0.7);
        strategy.setSignY(0.59);
        List<ConcatSignAddReq.SignStrategy> list = new ArrayList<>();
        list.add(strategy);
        concatSignAddReq.setSignStrategyList(list);
        ValidatorUtils.verify(concatSignAddReq, ConcatSignAddReq.class);
        //添加签约方
        addSigner(concatSignAddReq);
        //获取合同文件链接
        String downloadContract = downloadContract(req.getContractNo());
        return downloadContract;
    }
}
